home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Tools & Apps / Devices & Hardware / NuBus⁄Slot Manager / Declaration ROMs / Ex Apple Video ROM / Ex Apple Video Drvr next >
Encoding:
Text File  |  1990-09-14  |  44.7 KB  |  1,359 lines  |  [TEXT/MPS ]

  1. ; This is the source code to the Apple Video Driver. The specific-to-Apple Video card 
  2. ;register manipulations have been removed; you should use whatever is appropriate for your card.
  3.  
  4. ; This file is for information only, and is confidential. Do not distribute it. Questions should
  5. ; be directed to Mac Tech Support, “MacDTS” on either AppleLink or MCI Mail.
  6.  
  7.  
  8. ;
  9. ; File: TFBDriver.a
  10. ;
  11. ; To do:      Does the save stuff in the dCtlStorage make sense?? Is it enough?
  12. ;            If csMode = -1 on SetMode, then use mode, data in parameter RAM
  13. ;            Need to return the mode on the reset call.
  14. ;            *Allocate interrupt handler on open, deallocate on close, lock/unlock driver.
  15. ;            Add 8-bit mode.
  16. ;
  17. ;            SetMode needs to set the DCE dctlDevBase value (since a unique base is possible for each mode).
  18. ;
  19. ;            Should VidReset initialize Gamma and Color tables?
  20. ;----------------------------------------------------------------
  21. ;
  22. ;
  23. ;    Video Driver for TFB card.
  24. ;
  25. ;    Written by EB 2-Jun-86
  26. ;    Substantially modified    by GN Sept-... 1986
  27. ;
  28. ;-----------------------------------------------------------------
  29.  
  30.  
  31.             BLANKS        ON
  32.             STRING        ASIS
  33.             MACHINE        MC68020
  34.  
  35.             LOAD        'inc.sum.d'
  36.             LOAD        'nEqu.d'
  37.             INCLUDE        'colorEqu.a'
  38.             INCLUDE        'DepVideoEqu.a'
  39.             INCLUDE        'IndVideoEqu.a'
  40.             INCLUDE        'SlotIntEqu.a'
  41.     
  42. VideoDrvr    PROC        EXPORT
  43. ;=====================================================================
  44. ;    Local Vars, definitions, etc....
  45. ;=====================================================================
  46.  
  47. ; This is device storage which is stored in the dCtlStorage field of the DCE.
  48.  
  49. DCEPtr            EQU        0                        ; pointer to our DCE
  50. saveMode        EQU        DCEPtr+4                ; the current mode setting
  51. savePage        EQU        saveMode+2                ; the current page setting
  52. saveBaseAddr     EQU        savePage+2                ; the current base address
  53. saveSQElPtr     EQU        saveBaseAddr+4            ; the SQ element pointer (for _SIntRemove).
  54. GammaPtr         EQU        saveSQElPtr+4            ; the pointer to the Gamma correction table
  55. GFlags            EQU        GammaPtr+4                ; flags word
  56. VRAM256K        EQU        GFlags+2                ; boolean - TRUE if 256K vidRAM, FALSE if 512K
  57. dCtlSize        EQU        VRAM256K+2                ; size of dCtlStorage
  58.  
  59. ; Flags within GFlags word
  60.  
  61. GrayFlag        EQU        15                        ; luminance mapped if GFlags(GrayFlag) = 1
  62. IntDisFlag        EQU        14                        ; interrupts disabled if GFlags(IntFlag) =1
  63.  
  64. TFB1K            EQU        0
  65.  
  66. ;=====================================================================
  67. ;    Video Driver Header
  68. ;=====================================================================
  69.  
  70.     
  71. VidDrvr        DC.W    $4C00                    ; ctl,status,needsLock
  72.             DC.W    0,0,0                    ; not an ornament
  73.  
  74. ; Entry point offset table
  75.  
  76.             DC.W    VideoOpen-VidDrvr         ; open routine
  77.             DC.W    VidDrvr-VidDrvr            ; no prime
  78.             DC.W    VideoCtl-VidDrvr        ; control
  79.             DC.W    VideoStatus-VidDrvr        ; status
  80.             DC.W    VideoClose-VidDrvr        ; close
  81.  
  82.  
  83.             STRING        Pascal
  84. VideoTitle    DC.B        '.Display_Video_Apple_TFB'    ;
  85.             STRING        ASIS
  86.             ALIGN    2                        ; make sure we're aligned
  87.             DC.W    2                        ; version-2
  88.  
  89.  
  90. **********************************************************************
  91. *
  92. * VideoOpen allocates private storage for the device in the DCE and locks
  93. *    it down for perpituity. Also, install the interrupt handler and enable
  94. *    the interrupts.
  95. *   It also sets the default gamma table included in the driver
  96. *
  97. * Entry:    A0 = param block pointer
  98. *            A1 = DCE pointer
  99. *
  100. * Locals:    A2 = Saved param block pointer
  101. *            A3 = Saved DCE pointer
  102. *            A4 = Saved interrupt handler ptr.
  103. *
  104. **********************************************************************
  105.  
  106. ; Save registers
  107.  
  108. ;+++ for MPW 2.0 AIncludes!            WITH    VDPageInfo,SlotIntQElement
  109. VideoOpen    MOVE.L    A0,A2                        ;A2 <- param block pointer
  110.             MOVE.L    A1,A3                        ;A3 <- DCE pointer
  111.     
  112. ; Allocate private storage.
  113.             MOVEQ    #dCtlSize,D0                ; get size of parameters
  114.             _ResrvMem  ,SYS                     ; make room as low as possible
  115.             MOVEQ    #dCtlSize,D0                ; get size of parameters
  116.             _NewHandle ,SYS,CLEAR                ; get some memory for private storage
  117.             BNE      OpError                        ; => return an error in open
  118.             MOVE.L    A0,dCtlStorage(A3)            ; save returned handle in DCE
  119.             _HLock                                ; and lock it down
  120.     
  121. ; Get and install the interrupt handler.
  122.             LEA        BeginIH,A4                    ;Save Pointer to interrupt handler.
  123.             MOVEQ    #SQSize,D0                    ;allocate a slot queue element
  124.             _NewPtr    ,SYS,CLEAR                    ;get it from system heap cleared
  125.             BNE      OpError
  126.             MOVE.W    #SIQType,SQType(A0)            ;setup queue ID
  127.             MOVE.L    A4,SQAddr(A0)                ;setup int routine address
  128.             MOVE.L    dctlDevBase(A3),SQParm(A0)    ;save slot base addr as A3 parm
  129.             CLR.L    D0
  130.             MOVE.B    dctlSlot(A3),D0                ;setup slot #
  131.             _SIntInstall                        ;and do install
  132.             BNE.S    OpError
  133.  
  134.  
  135. ; Save SQElPtr for removal.
  136.             MOVE.L    dCtlStorage(A3),A1            ;Get pointer to private storage
  137.             MOVE.L    (A1),A1                        ;
  138.             MOVE.L    A0,saveSQElPtr(A1)            ;Save the SQ element pointer.
  139.  
  140. ; SO DRIVER DOESN'T CARRY REDUNDANT GAMMA TABLE, INITIALIZE DRIVER WITH LINEAR GAMMA TABLE.
  141. ; VALUES IN GAMMA TABLE ARE INVERTED SO WE DON'T NEED TO INVERT VALUES WE READ FROM IT.
  142.  
  143.             MOVEQ    #0,D0                        ; clear high word
  144.             MOVE    #256+GFormulaData,D0        ; get size of gamma table
  145.             _NewPtr    ,SYS,CLEAR                    ; allocate it in system heap
  146.             BNE.S    OpError                        ; =>failed! return error
  147.     
  148.             MOVE.L    A0,GammaPtr(A1)                ; else save off pointer
  149.             CLR.L    (A0)+                        ; version = 0, type = 0
  150.             MOVEQ    #1,D0
  151.             MOVE.L    D0,(A0)+                    ; formula size = 0, channel counte = 1
  152.             MOVE.L    #$01000008,(A0)+            ; 256 entries, 8 bits per entry
  153.             MOVE    #$FF,D0                        ; get count for dbra loop
  154. @NxtEntry    MOVE.B    D0,(A0)+                    ; set next byte
  155.             DBRA    D0,@NxtEntry                ; repeat until done
  156.  
  157. ; set luminance mapping and interrupts disabled to false
  158.  
  159.             CLR        GFlags(A1)                    ; set all flags false
  160.     
  161. ;
  162. ; size video RAM and save boolean in private storage
  163. ;
  164.  
  165.             MOVE.L    dctlDevBase(A3),A0                ;get base of vRAM
  166.             MOVE.L    #TestPos,D1                        ;get offset in D1
  167.             MOVE.L    #TestPat,(A0,D1.L)                ;write to alleged RAM
  168.             MOVE.L    #-1,-(SP)                        ;write out some garbage to clear data lines
  169.             CLR.L    (SP)+                            ;and pitch it
  170.             MOVE.L    (A0,D1.L),D0                    ;read pattern back
  171.             CMP.L    #TestPat,D0                        ;did it stick?
  172.             SNE        VRAM256K(A1)                    ;mark boolean (A1 still has private storage ptr)
  173.  
  174. ; Enable interrupts.
  175.  
  176.             ADD.L    #ClrVInt,A0                    ;bump to interrupt reg
  177.             CLR.B    (A0)                        ;clear it.
  178.  
  179.             MOVEQ    #0,D0                        ;no error
  180.             BRA.S    EndOpen
  181.  
  182.  
  183. ;  Error.
  184. OpError        MOVE.L    #OpenErr,D0                    ; say can't open driver
  185.  
  186.  
  187. EndOpen        RTS                                 ;return
  188.     
  189.     
  190. **********************************************************************
  191. *
  192. * VideoClose releases the device's private storage.
  193. *
  194. *
  195. * Entry:    A0 = param block pointer
  196. *            A1 = DCE pointer
  197. *
  198. * Locals:    A2 = Saved param block pointer
  199. *            A3 = Saved DCE pointer
  200. *            A4 = Temporary.
  201. *
  202. **********************************************************************
  203.  
  204. VideoClose    
  205.             MOVE.L    A0,A2                        ;A2 <- param block pointer
  206.             MOVE.L    A1,A3                        ;A3 <- DCE pointer
  207.  
  208.             MOVE.L    dCtlDevBase(A3),A4            ;A4 <- base address of device.
  209.             ADD.L    #DisableVInt,A4                ;Adjust the base
  210.             CLR.B    (A4)                        ;Disable interrupt from card
  211.  
  212.             MOVE.L    dCtlStorage(A3),A0            ;Get pointer to private storage
  213.             MOVE.L    (A0),A0                        ;
  214.             MOVE.L    saveSQElPtr(A0),A0            ;Get the SQ element pointer.
  215.             MOVE.B    dCtlSlot(A3),D0                ;get the slot of the interrupt handler
  216.             _SIntRemove                            ;Remove the interrupt handler.
  217.     
  218.             MOVE.L    dCtlStorage(A3),A0            ;Get pointer to private storage
  219.             MOVE.L    (A0),A0                        ;
  220.             MOVE.L    GammaPtr(A0),A0                ;get pointer to gamma table
  221.             _DisposPtr                            ;and dispose it
  222.     
  223.             MOVE.L    dCtlStorage(A3),A0            ;Dispose of the private storage.
  224.             _DisposHandle                        ;
  225.  
  226.  
  227.             MOVEQ    #0,D0                        ;get error into D0
  228.             RTS                                 ;return to caller
  229.  
  230. **********************************************************************
  231. *
  232. * Video Driver Control Call Handler.  Right now there are six calls:
  233. *
  234. *    (0)  Reset (VAR mode, page: INTEGER; VAR BaseAddr: Ptr);
  235. *    (1)  KillIO
  236. *    (2)     SetMode(mode, page: INTEGER; VAR BaseAddr: Ptr);
  237. *    (3)     SetEntries ( Table: Ptr; Start,Count : integer );
  238. *    (4)     SetGamma ( Table : Ptr );
  239. *   (5)  GrayPage (page);
  240. *   (6)  SetGray (csMode = 0 for color, 1 for gray)
  241. *    (7)     SetInterrupt (csMode = 0 to disable, 1 to enable)
  242. *
  243. *   Entry:     A0         = param block pointer
  244. *            A1         = DCE pointer
  245. *    Uses:    A2        = cs parameters (ie. A2 <- csParam(A0))  (must be preserved)
  246. *            A3         = scratch (doesn't need to be preserved)
  247. *            A4        = scratch (must be preserved)
  248. *            D0-D3     = scratch (don't need to be preserved)
  249. *
  250. *    Exit:    D0          = error code
  251. *
  252. **********************************************************************
  253.  
  254. ; Decode the call
  255. VideoCtl    MOVEM.L    A0/A4/D4,-(SP)                ; save work registers (A0 is saved because it is used by ExitDrvr).
  256.  
  257.             MOVE.W    csCode(A0),D0                ; get the opCode
  258.             MOVE.L    csParam(A0),A2                ; A2 <- Ptr to control parameters
  259.  
  260.             CMP.W    #7,D0                        ;IF csCode NOT IN [0..7] THEN
  261.             BHI.S    CtlBad                        ;  Error, csCode out of bounds.
  262.             LSL.W    #1,D0                        ;Adjust csCode to be an index into the table.
  263.             MOVE.W    CtlJumpTbl(PC,D0.W),D0        ;Get the relative offset to the routine.
  264.             JMP        CtlJumpTbl(PC,D0.W)            ;GOTO the proper routine.
  265.  
  266. CtlJumpTbl    DC.W    VidReset-CtlJumpTbl            ;$00 => VidReset
  267.             DC.W    CtlGood-CtlJumpTbl            ;$01 => CtlGood
  268.             DC.W    SetVidMode-CtlJumpTbl        ;$02 => SetVidMode
  269.             DC.W    SetEntries-CtlJumpTbl        ;$03 => SetEntries
  270.             DC.W    SetGamma-CtlJumpTbl            ;$04 => SetGamma
  271.             DC.W    GrayPage-CtlJumpTbl            ;$05 => GrayPage
  272.             DC.W    SetGray-CtlJumpTbl            ;$06 => SetGray
  273.             DC.W    SetInterrupt-CtlJumpTbl        ;$07 => SetInterrupt
  274.  
  275. SENoMem        ADDQ    #4,SP                        ; fix up the stack
  276. CtlBad        MOVEQ    #controlErr,D0                ; else say we don't do this one
  277.             BRA.S    CtlDone                        ; and return
  278.     
  279. CtlGood        MOVEQ    #noErr,D0                    ; return no error
  280.  
  281. CtlDone        MOVEM.L    (SP)+,A0/A4/D4                ; restore registers.
  282.             BRA        ExitDrvr
  283.  
  284.  
  285.     
  286. VidReset
  287. ;---------------------------------------------------------------------
  288. ;
  289. ;    Reset the card to its default (one bit per pixel)
  290. ;
  291. ;---------------------------------------------------------------------
  292.  
  293.             BSR        TFBInit                        ; initialize the card
  294.             MOVE    #OneBitMode,csMode(A2)        ; return default mode
  295.             MOVE    #1,D1                        ; get depth in D1
  296.             MOVEQ    #0,D0                        ; get page in D0
  297.             MOVE    D0,csPage(A2)                ; return the page
  298.             MOVE.L    dCtlStorage(A1),A3            ; get handle to our data
  299.             MOVE.L    (A3),A3                        ; A3 = our data
  300.             BSR        TFBSetDepth                    ; set the depth    from D1
  301.             BSR        TFBSetPage                    ; set the page from D0
  302.             MOVE.L    saveBaseAddr(A3),csBaseAddr(A2)    ; return the base address
  303.             BSR        GrayScreen                    ; paint the screen gray    
  304.             BRA.S    CtlGood                        ; => no error
  305.  
  306.  
  307.     
  308. SetVidMode
  309. ;---------------------------------------------------------------------
  310. ;
  311. ;    Set the card to the specified mode and page.  
  312. ;     If either is invalid, returns badMode error.
  313. ;
  314. ;   If the card is already set to the specified mode, then do nothing.
  315. ;
  316. ;    Note: Mode set is [1,2,4,8].
  317. ;
  318. ;---------------------------------------------------------------------
  319.  
  320.             MOVE.W    csMode(A2),D1                ; D1 = mode
  321.             BSR        ChkMode                        ; get mode, check, map to depth (1, 2, 4 or 8) {D1 <- depth}
  322.             BNE.S    CtlBad                        ; => not a valid mode
  323.     
  324.             MOVE.W    csPage(A2),D0                ; D0 = page
  325.             BSR        ChkPage                        ; check page    
  326.             BNE.S    CtlBad                        ; => not a valid page    
  327.  
  328. ; Only set the mode if it has changed
  329. ; TFBSetDepth and TFBSetPage update the saved data in the dCtlStorage
  330.  
  331. SetEm
  332.             MOVE.L    dCtlStorage(A1),A3            ; get handle to our data
  333.             MOVE.L    (A3),A3                        ; A3 = our data
  334.             MOVE.W    csMode(A2),D2                ; D2 = mode
  335.             CMP        saveMode(A3),D2                ; has the mode changed?    
  336.             BEQ.S    ModeOK1                        ; => no, check the page    
  337.             BSR        GrayTable                    ; set color table to gray
  338.             BSR        TFBSetDepth                    ; set the depth, get rowbytes
  339.             BSR        TFBSetPage                    ; set the page    
  340.             BRA.S    NoChange                    ; => and return
  341.     
  342. ModeOK1        BSR        TFBSetPage                    ; set the page    
  343.     
  344. NoChange    MOVE.L    saveBaseAddr(A3),csBaseAddr(A2)    ; return the base address
  345.             BRA.S    CtlGood                        ; => return no error
  346.  
  347.  
  348. GrayTable                                        ; new routine
  349. ;---------------------------------------------------------------------
  350. ;
  351. ;  Jam the entire color table to gray before switching modes.
  352. ;
  353. ;---------------------------------------------------------------------
  354.             MOVEM.L    A0-A1/D0-D1,-(SP)            ; save registers
  355.             MOVE    SR,-(SP)                    ; preserve status register
  356.             MOVE.W    #$2200,SR                    ; disable cursor interrupts
  357.             BSR        WaitVSync                    ; wait for next blanking period
  358.  
  359.             MOVE.L    dCtlStorage(A1),A0            ; get handle to private storage
  360.             MOVE.L    (A0),A0                        ; get pointer to storage (it's locked!)
  361.             MOVE.L    GammaPtr(A0),A0                ; get pointer to gamma data structure
  362.             MOVE    GFormulaSize(A0),D0            ; get the size of formula data
  363.             LEA        GFormulaData(A0),A0            ; point to formula data
  364.             ADD        D0,A0                        ; first correction table starts here
  365.             MOVE    #$80,D1                        ; get value for medium gray
  366.             MOVE.B    (A0,D1),D1                    ; get inverted, corrected gray
  367.  
  368.             MOVE.L    dCtlDevBase(A1),A0            ; A0 <- base address of device.
  369.             ADD.L    #ClrTbl+wCLUTDataReg,A0        ; add offset to color table data register
  370.             MOVE    #$FF,D0                        ; get count
  371. @Repeat        MOVE.B    D1,(A0)                        ; PUT RED COMPONENT
  372.             MOVE.B    D1,(A0)                        ; PUT GREEN COMPONENT
  373.             MOVE.B    D1,(A0)                        ; PUT BLUE COMPONENT
  374.             DBRA    D0,@Repeat                    ; UNTIL (entire table has been copied)
  375.             MOVE    (SP)+,SR                    ; restore the status reg
  376.             MOVEM.L    (SP)+,A0-A1/D0-D1            ; restore saved registers
  377.             RTS
  378.  
  379.  
  380. SetEntries
  381. ;---------------------------------------------------------------------
  382. ;
  383. ;    Input :
  384. ;            csParam -> datablock
  385. ;            datablock = csTable -> table of colorSpecs (not colortable)
  386. ;                        csStart -> where to start setting, or -1
  387. ;                        csCount -> # of entries to change
  388. ;
  389. ;      This call has two modes.  In SEQUENCE mode, csCount entries are changed
  390. ;    in the CLUT, starting at csStart.  In INDEX mode, csCount entries are
  391. ;    installed into the CLUT at the positions specified by their .value fields.
  392. ;    This mode is selected by passing csStart = -1.  In both cases, entries are
  393. ;    range-checked to the dynamic range of the video mode (bits/pixel).
  394. ;
  395. ;---------------------------------------------------------------------
  396. ;
  397. ;    Set the CLUT.
  398. ;        A0 = Ptr to the table.
  399. ;        A1 = Ptr to DCE.
  400. ;        A2 = Ptr to cs parameter record.
  401. ;        A3 = Ptr to Vert sync state or Ptr to CLUT
  402. ;        A4 = Ptr to gamma red table
  403. ;        A5 = Ptr to gamma green table
  404. ;        A6 = Ptr to gamma blue table
  405. ;
  406. ;        D0-D4 = Scratch
  407. ;       D5 = GRAY FLAG
  408. ;        D6 = Index range [0..n].
  409. ;        D7 = Shift constant (7,6,4 or 0).
  410. ;
  411. ;---------------------------------------------------------------------
  412.  
  413. ; Initialize loop.
  414.             MOVE.L    csTable(A2),D0                ; Check for a nil pointer.
  415.             BEQ.S    CtlBad
  416.     
  417.             MOVEM.L    A5-A6/D5-D7,-(SP)            ; save registers for gamma (A4/D4 saved by VideoCtl) 
  418.             MOVE.L    dCtlStorage(A1),A0            ; get handle to private storage
  419.             MOVE.L    (A0),A0                        ; get pointer to storage (it's locked!)
  420.             MOVE    GFLAGS(A0),D5                ; KEEP FLAGS WORD IN D5
  421.             MOVE.L    GammaPtr(A0),A0                ; get pointer to gamma data structure
  422.             MOVE.W    GFormulaSize(A0),D0            ; get the size of formula data
  423.             LEA        GFormulaData(A0),A4            ; point to formula data
  424.             ADD        D0,A4                        ; red correction table starts here    
  425.             MOVE.L    A4,A5                        ; get default pointer to green data    
  426.             MOVE.L    A4,A6                        ; get default pointer to blue data    
  427.             CMP        #1,GChanCnt(A0)                ; if only only one table, we're set    
  428.             BEQ.S    OneTbl                        ; => just one table    
  429.  
  430.             MOVE    GDataCnt(A0),D0                ; get # entries in table    
  431.             MOVE    GDataWidth(A0),D1            ; get width of each entry in bits
  432.             ADD        #7,D1                        ; round to nearest byte
  433.             LSR        #3,D1                        ; get bytes per entry
  434.             MULU    D1,D0                        ; get size of table in bytes
  435.  
  436.             ADDA    D0,A5                        ; calc base of green
  437.             ADDA    D0,A6                        ; calc base of blue    
  438.             ADDA    D0,A6                        ; calc base of blue    
  439.  
  440. OneTbl        SUB        #16*8,SP                    ; make room for 16 entries    
  441.     
  442. ; Get the index range (D6) and the shift constant (D7).
  443.  
  444.             BSR        CvtIndex
  445.             MOVE.L    csTable(A2),A0                ; get colorSpec pointer in A0
  446.     
  447. ; If it is sequence mode, then go do fast way
  448.  
  449.             MOVE.W    csStart(A2),D1                ; D1 = mode/start    
  450.             BMI.S    NoSequence                    ; => not sequential    
  451.             CMP        #255,D6                        ; doing 256 entries?
  452.             BNE.S    SLOSEQUENCE                    ; =>NO, NOT 8 BIT MODE
  453.             CMP        #4,csCount(A2)                ; MORE THAN 4 ENTRIES?
  454.             BGT        SEQUENCE                    ; =>yes, fast special case
  455.  
  456. ; For 4-bit and less, set up a color table on the stack that has indices
  457.  
  458. SloSequence    MOVE.L    SP,A3                        ; point to stackSpecs
  459.             MOVE    csCount(A2),D0                ; get elements to copy
  460.  
  461. @NxtSpec    MOVE    D1,(A3)+                    ; copy index into stackSpec    
  462.             MOVE.L    (A0)+,D2                    ; get index, red    
  463.             MOVE    D2,(A3)+                    ; copy red    
  464.             MOVE.L    (A0)+,(A3)+                    ; copy green, blue    
  465.             ADDQ    #1,D1                        ; bump to next index
  466.             DBRA    D0,@NxtSpec                    ; => repeat for all specs    
  467.     
  468.             MOVE.L    SP,A0                        ; get colorSpec pointer in A0
  469.  
  470. ; disable cursor interrupts so that there will be time to change colors
  471. ; A0 already contains the pointer to colorSpecs
  472.  
  473. NoSequence    MOVE    SR,-(SP)                    ; set disable interrupt disable up to level 2 
  474.             MOVE.W    #$2200,SR                    ;  
  475.     
  476.             BSR        WaitVSync                    ; wait for next blanking period (preserves A0)
  477.  
  478. ; Copy the table to the CLUT
  479.  
  480.             MOVE.W    csCount(A2),D0                ; get the number of elements to change
  481.     
  482. @Repeat        MOVE.L    (A0)+,D2                    ; GET INDEX, RED
  483.             SWAP    D2                            ; GET INDEX
  484.             MOVEQ    #-1,D1                        ; SET HIGH BITS FOR ROL.L
  485.             MOVE    D2,D1                        ; AND MOVE INTO D1
  486.             CMP.W    D6,D1                        ; IF D1 > MAXINDEX THEN
  487.             BHI.S    @Until                        ; INDEX OUT OF RANGE
  488.     
  489.             SWAP    D2                            ; LEAVE RED IN D2
  490.             MOVE.L    (A0)+,D3                    ; GET GREEN,BLUE
  491.             MOVE.L    D3,D4                        ; GET BLUE IN D4.W
  492.             SWAP    D3                            ; GET GREEN IN D3.W
  493.             TST        D5                            ; TEST FLAGS WORD
  494.             BPL.S    @NOGRAY                        ; =>DON'T DO LUMINANCE MAPPING
  495.  
  496.             MULU    #$4CCC,D2                    ; MULTIPLY BY WEIGHT FOR RED
  497.             MULU    #$970A,D3                    ; MULTIPLY BY WEIGHT FOR GREEN
  498.             MULU    #$1C28,D4                    ; MULTIPLY BY WEIGHT FOR BLUE
  499.             ADD.L    D3,D2                        ; GET SUM OF RED, GREEN
  500.             ADD.L    D4,D2                        ; AND BLUE INTO D2
  501.             ROL.L    #8,D2                        ; GET HIGH BYTE AS LUMINANCE
  502.             AND        #$00FF,D2                    ; MAKE D2 A BYTE INDEX
  503.             MOVE.B    (A4,D2),D2                    ; GET GAMMA CORRECTED GRAY
  504.         ; Put value in D2 to all three components on video card
  505.             DBRA    D0,@Repeat                    ; UNTIL (entire table has been copied)
  506.             BRA.S    @NOMORE                        ; => RETURN
  507.  
  508. @NOGRAY        ROR        #8,D2                        ; GET HIGH BYTE OF RED
  509.             MOVEQ    #0,D1                        ; CLEAR OUT INDEX
  510.             MOVE.B    D2,D1                        ; AND GET BYTE INDEX
  511.             MOVE.B    (A4,D1),D1                    ; GET INVERTED, CORRECTED RED
  512.         ; Put red value to color table on card
  513.     
  514.             ROR        #8,D3                        ; GET HIGH BYTE OF GREEN
  515.             MOVEQ    #0,D1                        ; CLEAR OUT INDEX
  516.             MOVE.B    D3,D1                        ; AND GET BYTE INDEX
  517.             MOVE.B    (A5,D1),D1                    ; GET INVERTED, CORRECTED GREEN
  518.         ; Put green value to color table on card
  519.     
  520.             ROR        #8,D4                        ; GET HIGH BYTE OF BLUE
  521.             MOVEQ    #0,D1                        ; CLEAR OUT INDEX
  522.             MOVE.B    D4,D1                        ; AND GET BYTE INDEX
  523.             MOVE.B    (A6,D1),D1                    ; GET INVERTED, CORRECTED BLUE
  524.         ; Put blue value to color table on card
  525.     
  526. @Until        DBRA    D0,@Repeat                    ; UNTIL (entire table has been copied)
  527.     
  528. @NOMORE        MOVE.W    (SP)+,SR                    ; restore the status reg    
  529.             ADD        #16*8,SP                    ; strip stackSpecs
  530.             MOVEM.L    (SP)+,A5/A6/D5-D7            ; restore saved registers    
  531.     
  532.             BRA        CtlGood                        ; => return no error
  533.  
  534. SEQUENCE
  535.  
  536. ; make sure the stack is long aligned, and allocate buffer on stack
  537.  
  538.             MOVE.L    SP,D1                        ; get stack
  539.             MOVE.L    D1,D0                        ; copy stack
  540.             NEG        D0                            ; get amount to subtract
  541.             AND        #$3,D0                        ; get low bits
  542.             BEQ.S    StkOk                        ; => already long aligned
  543.             SUB        D0,SP                        ; else make stack long aligned
  544. StkOk        MOVE.L    D1,-(SP)                    ; save original stack on stack
  545.     
  546.             _StackSpace                            ; how much room is left on stack?
  547.             CMP.L    #$400+$100,D0                ; enough for 1024+256 slop?    
  548.             BLT        SENoMem                        ; sorry, not enough    
  549.  
  550.             SUB        #$400,SP                    ; make room for 256*4 bytes
  551.  
  552. ; build the color table on the stack
  553.  
  554.             MOVE    csStart(A2),D1                ; get the starting element
  555.             LEA        0(SP,D1*4),A3                ; A3 = pointer to first stack element
  556.             MOVE.W    csCount(A2),D0                ; get the number of elements to change
  557.             MOVE.L    csTable(A2),A0                ; get a pointer to the table of colorspecs    
  558.  
  559. @Repeat        CMP        D6,D1                        ; check index against max
  560.             BGT.S    NoMore                        ; => oops, table is full
  561.  
  562.             TST        D5                            ; TEST FLAGS WORD
  563.             BPL.S    @NOGRAY                        ; =>DON'T DO LUMINANCE MAPPING
  564.     
  565.             MOVE.L    (A0)+,D2                    ; GET RED IN D2.W
  566.             MOVE.W    (A0)+,D3                    ; GET GREEN IN D3.W
  567.             MOVE.W    (A0)+,D4                    ; GET BLUE IN D4.W
  568.     
  569.             MULU    #$4CCC,D2                    ; MULTIPLY BY WEIGHT FOR RED
  570.             MULU    #$970A,D3                    ; MULTIPLY BY WEIGHT FOR GREEN
  571.             MULU    #$1C28,D4                    ; MULTIPLY BY WEIGHT FOR BLUE
  572.             ADD.L    D3,D2                        ; GET SUM OF RED, GREEN
  573.             ADD.L    D4,D2                        ; AND BLUE INTO D2
  574.             ROL.L    #8,D2                        ; GET HIGH BYTE AS LUMINANCE
  575.             MOVEQ    #0,D3                        ; CLEAR HIGH PART
  576.             MOVE.B    D2,D3                        ; GET THE CORRECTED BLUE
  577.             MOVE.B    (A4,D3),D2                    ; GET INVERTED, GAMMA CORRECTED GRAY
  578.  
  579.             MOVE.B    D2,D3                        ; GET THE CORRECTED BLUE
  580.             LSL.L    #8,D3                        ; D3 = 00B0
  581.             MOVE.B    D2,D3                        ; D3 = 00BG
  582.             LSL.L    #8,D3                        ; D3 = 0BG0
  583.             MOVE.B    D2,D3                        ; D3 = 0BGR
  584.             MOVE.L    D3,(A3)+                    ; put blue, green, red to stack
  585.             ADDQ    #1,D1                        ; bump index
  586.             DBRA    D0,@Repeat                    ; UNTIL (entire table has been copied)
  587.             BRA.S    NOMORE                        ; => RETURN
  588.  
  589. @NOGRAY        MOVEQ    #0,D2                        ; clear high part
  590.             MOVE.B    rgb+blue(A0),D2                ; get blue
  591.             MOVE.B    (A4,D2),D3                    ; get the gamma corrected blue
  592.             LSL.L    #8,D3                        ; D3 = xxBx
  593.             MOVE.B    rgb+green(A0),D2            ; get green
  594.             MOVE.B    (A5,D2),D3                    ; get the gamma corrected green
  595.             LSL.L    #8,D3                        ; D3 = xBGx
  596.             MOVE.B    rgb+red(A0),D2                ; get red
  597.             MOVE.B    (A6,D2),D3                    ; get the gamma corrected red (D3 = xBGR)
  598.             MOVE.L    D3,(A3)+                    ; put blue, green, red to stack
  599.  
  600.             ADDQ    #1,D1                        ; bump index
  601.             ADDQ    #8,A0                        ; point to next color spec
  602. @Until        DBRA    D0,@Repeat                    ; UNTIL (entire table has been copied)
  603.     
  604. NoMore        MOVE.W    SR,-(SP)                    ; set disable interrupt disable up to level 2 
  605.             MOVE.W    #$2200,SR                    ;  
  606.             MOVE.L    A3,A0                        ; save pointer to last element inserted
  607.     
  608.             BSR        WaitVSync                    ; wait for vertical blanking
  609.     
  610.             MOVEQ    #0,D1                        ; clear out D1
  611.             MOVE.B    csStart+1(A2),D1            ; get the starting element to change
  612.             NOT.B    D1                            ; negate for position of starting element
  613.             MOVE.W    csCount(A2),D0                ; get the number of elements to change
  614.             SUB.W    D0,D1                        ; calc first element to change
  615.             NOT.B    D1                            ; and negate for nubus
  616.  
  617. NextRGB        MOVE.L    -(A0),D1                    ; get B,G,R
  618.         ; set red
  619.             LSR.L    #8,D1                        ; get green
  620.         ; set green
  621.             LSR.L    #8,D1                        ; get blue
  622.         ; set green
  623.             DBRA    D0,NextRGB                    ; => repeat for next RGB
  624.     
  625.             MOVE.W    (SP)+,SR                    ; restore the status reg    
  626.             ADD        #$400,SP                    ; strip stack frame
  627.             MOVE.L    (SP)+,SP                    ; restore stack alignment
  628.             ADD        #16*8,SP                    ;
  629.             MOVEM.L    (SP)+,A5/A6/D5-D7            ; restore saved registers    
  630.     
  631.             BRA        CtlGood                        ; => return no error
  632.  
  633.  
  634. SetGamma                                        ; <C522/15Dec86> DAF
  635. ;---------------------------------------------------------------------
  636. ;
  637. ;    Set the gamma table
  638. ;        A0 = Ptr to private storage
  639. ;        A1 = Ptr to DCE
  640. ;        A2 = Ptr to cs parameter record
  641. ;
  642. ;---------------------------------------------------------------------
  643.     
  644. ; get new gamma table and check that we know how to handle it
  645.     
  646.             MOVE.L    A1,-(SP)                        ; save DCE pointer
  647.             MOVE.L    dCtlStorage(A1),A3                ; get handle to private storage
  648.             MOVE.L    (A3),A3                            ; get pointer to storage
  649.  
  650.             MOVE.L    csGTable(A2),D0                    ; test for a NIL pointer
  651.             BEQ        @BadCtl                            ; if so, then bad result
  652.             MOVE.L    D0,A1                            ; get pointer to new gamma table
  653.     
  654.             TST.L    GVersion(A1)                    ; version, type = 0?
  655.             BNE        @BadCtl                            ; => no, return error
  656.             CMP        #8,GDataWidth(A1)                ; is data width 8?
  657.             BNE        @BadCtl                            ; => no, return error
  658.             CMP        #256,GDataCnt(A1)                ; 256 values per channel?
  659.             BNE.S    @BadCtl                            ; => no, return error
  660.     
  661. ; if new table is different size, reallocate memory
  662.     
  663.             MOVE.L    GammaPtr(A3),A0                    ; get current gamma in A0
  664.             MOVE    GFormulaSize(A1),D0                ; get size of formula in new
  665.             CMP        GFormulaSize(A0),D0                ; same as current gamma table
  666.             BNE.S    @GetNew                            ; =>no, resize pointer
  667.             MOVE    GChanCnt(A1),D0                    ; get number of tables in new
  668.             CMP        GChanCnt(A0),D0                    ; same as current gamma table?
  669.             BEQ.S    @SizeOK                            ; => yes, data size ok
  670.             BGT.S    @GetNew                            ; => new one is bigger, save old one
  671. @NewSize    _DisposPtr                                ; if new one smaller, dispose old one
  672.             CLR.L    GammaPtr(A3)                    ; flag it's been disposed
  673.     
  674. @GetNew        MOVE    #256,D0                            ; get number of entries
  675.             MULU    GChanCnt(A1),D0                    ; multiply by number of tables
  676.             ADD        GFormulaSize(A1),D0                ; add size of formula data
  677.             ADD        #GFormulaData,D0                ; add gamma table header size
  678.             _NewPtr ,Sys                            ; and allocate a new pointer
  679.             BNE.S    @BadCtl                            ; => unable to allocate storage
  680.     
  681.             MOVE.L    GammaPtr(A3),D0                    ; get old gamma table
  682.             MOVE.L    A0,GammaPtr(A3)                    ; save new gamma table
  683.             TST.L    D0                                ; was there an old one?
  684.             BEQ.S    @SizeOK                            ; => no, already disposed
  685.             MOVE.L    D0,A0                            ; else get old table
  686.             _DisposPtr                                ; and dispose of old gamma table
  687.     
  688.             MOVE.L    GammaPtr(A3),A0                    ; get new gamma table back
  689.  
  690. ; copy the gamma table header
  691.     
  692. @SizeOK        MOVE    GChanCnt(A1),D0                    ; get number of tables
  693.             MOVE    GFormulaSize(A1),D1                ; get size of formula data
  694.             MOVE.L    (A1)+,(A0)+                        ; copy gamma header
  695.             MOVE.L    (A1)+,(A0)+                        ; which is
  696.             MOVE.L    (A1)+,(A0)+                        ; 12 bytes long ***
  697.     
  698. ; copy the data, inverted for nubus
  699.     
  700.             MOVE    #256,D2                            ; get number of entries
  701.             MULU    D0,D2                            ; multiply by number of tables
  702.             ADD        D1,D2                            ; add in size of formula data
  703.             SUBQ    #1,D2                            ; get count - 1
  704. @NxtByte    MOVE.B    (A1)+,D0                        ; get a byte
  705.             NOT.B    D0                                ; invert it for nubus
  706.             MOVE.B    D0,(A0)+                        ; move a byte
  707.             DBRA    D2,@NxtByte                        ; => repeat for all bytes
  708.  
  709.             MOVE.L    (SP)+,A1                        ; restore DCE pointer
  710.             BRA        CtlGood                            ; => return no error
  711.  
  712. @BadCtl        MOVE.L    (SP)+,A1                        ; restore DCE pointer
  713.             BRA        CtlBad                            ; => return an error
  714.  
  715.  
  716.  
  717.  
  718. GrayPage                                            ; <EHB12/16>
  719. ;---------------------------------------------------------------------
  720. ;
  721. ;    Clear the specified page in the current mode to gray
  722. ;
  723. ;        A0 = Ptr to private storage
  724. ;        A1 = Ptr to DCE
  725. ;        A2 = Ptr to cs parameter record
  726. ;
  727. ;---------------------------------------------------------------------
  728.     
  729.             MOVE.L    dCtlStorage(A1),A3                ; get handle to our storage
  730.             MOVE.L    (A3),A3                            ; get pointer to our storage
  731.             MOVE    saveMode(A3),D1                    ; D1 = mode
  732.             BSR        ChkMode                            ; convert mode to depth in D1
  733.             BNE        CtlBad                            ; => not a valid depth
  734.     
  735.             MOVE    csPage(A2),D0                    ; D0 = page
  736.             BSR        ChkPage                            ; check page    
  737.             BNE     CtlBad                            ; => not a valid page    
  738.  
  739.             BSR        GrayScreen                        ; paint the screen gray    
  740.  
  741.             BRA        CtlGood                            ; => return no error    
  742.  
  743.  
  744. SetGray
  745. ;---------------------------------------------------------------------
  746. ;
  747. ;    Set luminance mapping on (csMode = 1) or off (csMode = 0)
  748. ;
  749. ;   When luminance mapping is on, RGB values passed to setEntries are mapped
  750. ;     to grayscale equivalents before they are written to the CLUT.
  751. ;
  752. ;        A0 = Ptr to private storage
  753. ;        A1 = Ptr to DCE
  754. ;        A2 = Ptr to cs parameter record
  755. ;
  756. ;---------------------------------------------------------------------
  757.     
  758.             MOVE.L    dCtlStorage(A1),A3                ; get handle to our storage
  759.             MOVE.L    (A3),A3                            ; get pointer to our storage
  760.             MOVE    GFlags(A3),D0                    ; get current flags word
  761.             MOVE.B    csMode(A2),D1                    ; get boolean
  762.             BFINS    D1,D0{16:1}                        ; set grayFlag
  763.             MOVE    D0,GDFlags(A3)
  764.             BRA        CtlGood                            ; => return no error
  765.  
  766.  
  767. SetInterrupt
  768. ;---------------------------------------------------------------------
  769. ;
  770. ;    Enable (csMode = 0) or disable (csMode = 1) VBL interrupts
  771. ;
  772. ;   As a future performance enhancement, interrupts on the card can be
  773. ;    disabled or enabled from software. For instance, if the cursor is
  774. ;    not on a screen, and there is nothing in the Slot Interrupt Queue
  775. ;    for that device, interrupts may be disabled reducing interrupt 
  776. ;    overhead for the system.
  777. ;
  778. ;        A0 = Ptr to private storage
  779. ;        A1 = Ptr to DCE
  780. ;        A2 = Ptr to cs parameter record
  781. ;
  782. ;---------------------------------------------------------------------
  783.  
  784. ;+++ for MPW 2.0 AIncludes!            WITH    VDPageInfo,SlotIntQElement
  785.     
  786.             MOVE.L    dCtlStorage(A1),A3                ; get handle to our storage
  787.             MOVE.L    (A3),A3                            ; get pointer to our storage
  788.             MOVE    GFlags(A3),D0                    ; get current flags word
  789.             MOVE.B    csMode(A2),D1                    ; get boolean
  790.             BFINS    D1,D0{17:1}                        ; set IntFlag
  791.             MOVE    D0,GDFlags(A3)                    ; put flag word back
  792.     
  793.             BTST    #IntDisFlag,D0                    ; is the flag on or off?
  794.             BEQ.S    EnableThem                        ; if zero, then enable
  795.     
  796. ; this code disables VBL interrupts, then removes the interrupt handler
  797.     
  798.             BSR        WaitVSync                        ; to be safe, wait for the next VBL
  799.             MOVE.L    dCtlDevBase(A1),A1                ; get the device base
  800.             ADD.L    #DisableVInt,A1                    ; point to hardware register
  801.             CLR.B    (A1)                            ; hit the register
  802.  
  803.             MOVE.L    saveSQElPtr(A0),A0                ; get the SQ element pointer
  804.             _SIntRemove                                ; remove the interrupt handler
  805.             BRA        CtlGood                            ; done
  806.  
  807. EnableThem    
  808.             MOVE.L    A0,A2                             ; save private pointer
  809.             LEA        BeginIH,A4                        ; save Pointer to interrupt handler
  810.             MOVEQ    #SQSize,D0                        ; allocate a slot queue element
  811.             _NewPtr    ,SYS,CLEAR                        ; get it from system heap cleared
  812.             BNE      CtlBad                            ; if not allocated, return bad
  813.             MOVE.W    #SIQType,SQType(A0)                ; setup queue ID
  814.             MOVE.L    A4,SQAddr(A0)                    ; setup int routine address
  815.             MOVE.L    dctlDevBase(A1),SQParm(A0)        ; save slot base addr as A3 parm
  816.             CLR.L    D0
  817.             MOVE.B    dctlSlot(A1),D0                    ; setup slot #
  818.             _SIntInstall                            ; and do install
  819.             BNE     CtlBad
  820.     
  821.             MOVE.L    A0,saveSQElPtr(A2)                ; save the queue element for eventual disposal
  822.             MOVE.L    dctlDevBase(A1),A0                ; get hardware base
  823.             ADD.L    #ClrVInt,A0                        ; hit the clear register (which also enables)
  824.             CLR.B    (A0)                            ; start interrupts happening
  825.  
  826.             BRA        CtlGood                            ; and go home
  827. ;+++    ENDWITH
  828.  
  829. **********************************************************************
  830. *
  831. * Video Driver Status Call Handler.  Right now there are eight calls:
  832. *
  833. *    (0)  Error
  834. *    (1)  Error
  835. *    (2)     GetMode
  836. *    (3)  GetEntries
  837. *    (4)     GetPage
  838. *    (5)     GetPageBase
  839. *    (6)  GetGray
  840. *    (7)     GetInterrupt
  841. *    (8)     GetGamma    
  842. *
  843. *   Entry:     A0         = param block
  844. *            A1         = DCE pointer
  845. *    Uses:    A2        = cs parameters (ie. A2 <- csParam(A0))  (must be preserved)
  846. *            A3         = scratch (doesn't need to be preserved)
  847. *            D0-D3     = scratch (don't need to be preserved)
  848. *
  849. *    Exit:    D0          = error code
  850. *
  851. **********************************************************************
  852.  
  853. VideoStatus    
  854.             MOVE.L    A0,-(SP)                    ; save a register
  855.             MOVE.W    csCode(A0),D0                ; get the opCode
  856.             MOVE.L    csParam(A0),A2                ; A2 <- Ptr to control parameters
  857.     
  858.  
  859.             CMP.W    #6,D0                        ;IF csCode NOT IN [0..6] THEN
  860.             BHI.S    StatBad                        ;  Error, csCode out of bounds.
  861.             LSL.W    #1,D0                        ;Adjust csCode to be an index into the table.
  862.             MOVE.W    StatJumpTbl(PC,D0.W),D0        ;Get the relative offset to the routine.
  863.             JMP        StatJumpTbl(PC,D0.W)        ;GOTO the proper routine.
  864.  
  865. StatJumpTbl    DC.W    StatBad-StatJumpTbl            ;$00 => Error
  866.             DC.W    StatBad-StatJumpTbl            ;$01 => Error
  867.             DC.W    GetMode-StatJumpTbl            ;$02 => GetMode
  868.             DC.W    GetEntries-StatJumpTbl        ;$03 => GetEntries {NOT YET}
  869.             DC.W    GetPage-StatJumpTbl            ;$04 => GetPage
  870.             DC.W    GetPageBase-StatJumpTbl        ;$05 => GetPageBase
  871.             DC.W    GetGray-StatJumpTbl            ;$06 => GetGray
  872.             DC.W    GetInterrupt-StatJumpTbl    ;$07 => GetInterrupt
  873.             DC.W    GetGamma-StatJumpTbl        ;$08 => GetGamma
  874.     
  875. StatBad        MOVEQ    #statusErr,D0                ; else say we don't do this one
  876.             BRA        StatDone                    ; and return
  877.     
  878. StatGood    MOVEQ    #noErr,D0                    ; return no error
  879.  
  880. StatDone    MOVE.L    (SP)+,A0                    ; restore saved register
  881.             BRA        ExitDrvr
  882.  
  883.  
  884. GetMode
  885. ;---------------------------------------------------------------------
  886. ;
  887. ;    Return the current mode
  888. ;
  889. ;---------------------------------------------------------------------
  890.  
  891.             MOVE.L    dCtlStorage(A1),A3                ; get handle to our storage
  892.             MOVE.L    (A3),A3                            ; get pointer to our storage
  893.             MOVE.W    saveMode(A3),csMode(A2)            ; return the mode
  894.             MOVE.W    savePage(A3),csPage(A2)            ; return the page number
  895.             MOVE.L    saveBaseAddr(A3),csBaseAddr(A2)    ; and the base address
  896.     
  897.             BRA.S    StatGood                        ; => return no error
  898.     
  899.  
  900. GetEntries
  901. ;---------------------------------------------------------------------
  902. ;
  903. ;    Get the CLUT.
  904. ;
  905. ;---------------------------------------------------------------------
  906.  
  907. ; Initialize loop.
  908.             MOVE.L    csTable(A2),D0                ; Check for a nil pointer.
  909.             BEQ.S    StatBad
  910.             MOVE.L    D0,A0                        ; A0 <- pointer to table.
  911.     
  912.             CMP.W    #-1,csStart(A2)                ; is it index or sequence mode?
  913.             BEQ.S    GECom                        ; if index, then continue
  914.     
  915.             MOVE.W  csCount(A2),D0              ; get the count
  916.             MOVE.W  D0,D1                       ; make a copy for index loop 
  917.             MOVE.W    D0,D2                        ; make a copy of the count    
  918.             ADD.W    csStart(A2),D2                ; get last index
  919. @1
  920.             MOVE.W    D2,value(A0,D1*8)            ; write the index into the table
  921.             SUBQ    #1,D2                        ; decrease index
  922.             DBRA    D1,@1                        ; for all indices
  923.  
  924. GECom    
  925.  
  926.             MOVEM.L    D6-D7,-(SP)                    ; SAVE WORK REGISTERS
  927.  
  928. ; Get the index range (D6) and the shift constant (D7).
  929.             BSR        CvtIndex
  930.  
  931. ; Copy the CLUT to the Table
  932.     
  933.                                                 ; REPEAT
  934. @Repeat        MOVE.W    value(A0),D1                ;   D1 <- xindex.
  935.             CMP.W    D6,D1                        ;   IF D1 > D6 THEN
  936.             BHI.S    @Until                        ;     GOTO @Until {Index is out of range for this mode}
  937.     
  938.             OR.L    #$FFFF0000,D1                ;   get ones in hi half of d1.<C389/10Nov86>    
  939.             ROL.L    D7,D1                        ;   shift it.                   <C389/10Nov86>
  940.  
  941.         ; Get red into D1
  942.             NOT.W    D1   
  943.             MOVE.B    D1,rgb+red(A0)    
  944.             MOVE.B    D1,rgb+red+1(A0)                ;    <C715>
  945.     
  946.         ; Get green into D1
  947.             NOT.W    D1   
  948.             MOVE.B    D1,rgb+green(A0)    
  949.             MOVE.B    D1,rgb+green+1(A0)            ;    <C715>
  950.     
  951.         ; Get blue into D1
  952.             NOT.W    D1   
  953.             MOVE.B    D1,rgb+blue(A0)
  954.             MOVE.B    D1,rgb+blue+1(A0)            ;   <C715>
  955.     
  956. @Until        ADDQ.L    #cSpecRec,A0                ;   A0 <- next entry in the table.
  957.             DBRA    D0,@Repeat                    ; UNTIL (entire table has been copied)
  958.     
  959.             MOVEM.L    (SP)+,D6-D7                    ; RESTORE WORK REGISTERS
  960.     
  961.             BRA        StatGood                    ; => return no error
  962.  
  963.  
  964.  
  965.     
  966. GetPage
  967. ;---------------------------------------------------------------------
  968. ;
  969. ;    Return the number of pages in the specified mode
  970. ;
  971. ;---------------------------------------------------------------------
  972.  
  973.             MOVE    csMode(A2),D1                ; get the mode
  974.             BSR        ChkMode                        ; check mode, get depth in D1
  975.             BNE        StatBad                        ; => not a valid mode
  976.  
  977.             MOVE.L    dCtlStorage(A1),A0            ; get private storage pointer
  978.             TST.B    VRAM256K(A0)                ; 512K or 256K?    
  979.             BNE.S    @1                            ; if TRUE, then 256K of RAM    
  980.             MOVEQ    #4,D0                        ; if FALSE, 512K vRAM (and 1 more page per mode)
  981.             BRA.S    @2
  982. @1            MOVEQ    #3,D0                        ; get one-bit page count    
  983. @2            DIVU    D1,D0                        ; divide by depth    
  984.             ADD        #1,D0                        ; make it one based    
  985.             MOVE    D0,csPage(A2)                ; return page count    
  986.             BRA        StatGood                    ; => return no error
  987.     
  988.     
  989.     
  990. GetPageBase
  991. ;---------------------------------------------------------------------
  992. ;
  993. ;    Return the base address for the specified page in the current mode
  994. ;
  995. ;---------------------------------------------------------------------
  996.     
  997.             MOVE.L    dCtlStorage(A1),A3            ; get handle to our storage    
  998.             MOVE.L    (A3),A3                        ; get pointer to our storage
  999.             MOVE    saveMode(A3),D1                ; get the current mode
  1000.             BSR        ChkMode                        ; convert to depth in D1    
  1001.             MOVE.W    csPage(A2),D0                ; get the requested page    
  1002.             BSR        ChkPage                        ; is the page valid?
  1003.             BNE        StatBad                        ; => no, just return
  1004.  
  1005.             MOVE    saveMode(A3),D1                ; get the current mode
  1006.             SUB        #OneBitMode,D1                ; make it 0 based    
  1007.             LEA        ModeTbl,A0                    ; point to tables    
  1008.             MULU    4(A0,D1*8),D0                ; calc page * rowBytes
  1009.             MULU    6(A0,D1*8),D0                ; calc page * rowBytes * height
  1010.             MOVEQ    #defmBaseOffset,D1            ; add offset for TFB
  1011.             ADD.L    D1,D0                        ; which doesn't use first long
  1012.             ADD.L    dCtlDevBase(A1),D0            ; add base address for card    
  1013.             MOVE.L    D0,csBaseAddr(A2)            ; return the base address    
  1014.     
  1015.             BRA     StatGood                    ; => return no error
  1016.     
  1017.  
  1018. GetGray
  1019. ;---------------------------------------------------------------------
  1020. ;
  1021. ;    Return a boolean, set true if luminance mapping is on
  1022. ;
  1023. ;---------------------------------------------------------------------
  1024.  
  1025.             CLR        csMode(A2)                    ; assume that grayFlag is false
  1026.             MOVE.L    dCtlStorage(A1),A3            ; get handle to our storage
  1027.             MOVE.L    (A3),A3                        ; get pointer to our storage
  1028.             TST        GFlags(A3)                    ; is luminance mapping on?
  1029.             BPL        StatGood                    ; => no, return false
  1030.             MOVE.B    #1,csMode(A2)                ; else return true
  1031.             BRA        StatGood                    ; => and return
  1032.     
  1033.  
  1034. GetInterrupt
  1035. ;---------------------------------------------------------------------
  1036. ;
  1037. ;    Return a boolean in csMode, set true if VBL interrupts are disabled
  1038. ;
  1039. ;---------------------------------------------------------------------
  1040.  
  1041.             CLR        csMode(A2)                    ; assume that grayFlag is false
  1042.             MOVE.L    dCtlStorage(A1),A3            ; get handle to our storage
  1043.             MOVE.L    (A3),A3                        ; get pointer to our storage
  1044.             BTST    #IntDisFlag,GFlags(A3)        ; is luminance mapping on?
  1045.             BEQ        StatGood                    ; => no, return false
  1046.             MOVE.B    #1,csMode(A2)                ; else return true
  1047.             BRA        StatGood                    ; => and return
  1048.     
  1049.  
  1050. GetGamma
  1051. ;---------------------------------------------------------------------
  1052. ;
  1053. ;    Return the handle to the current gamma table
  1054. ;
  1055. ;---------------------------------------------------------------------
  1056.  
  1057.             MOVE.L    dCtlStorage(A1),A3                ; get handle to our storage
  1058.             MOVE.L    (A3),A3                            ; get pointer to our storage
  1059.             MOVE.L    GammaPtr(A3),csGTable(A2)        ; return the pointer to the structure
  1060.             BRA        StatGood                        ; and return a good result
  1061.     
  1062.  
  1063. ;=====================================================================
  1064. ;
  1065. ;    Special.
  1066. ;
  1067. ;=====================================================================
  1068.  
  1069.  
  1070. ;---------------------------------------------------------------------
  1071. ;
  1072. ;    Wait for vertical blanking
  1073. ;
  1074. ;   A1 = DCE POINTER
  1075. ;---------------------------------------------------------------------
  1076.  
  1077. WaitVSync    
  1078.  
  1079.     IF NOT TFB1K THEN
  1080.  
  1081.             MOVEM.L    A0/D0,-(SP)                    ;save work registers
  1082.             MOVE    SR,-(SP)                    ;set disable interrupt disable up to level 2 
  1083.             MOVE.W    #$2200,SR                    ;  
  1084.     
  1085.         ; Loop until Vertical Blanking signal
  1086.     
  1087.             MOVE    (SP)+,SR                    ;RE-ENABLE CURSOR INTERRUPTS
  1088.             MOVEM.L    (SP)+,A0/D0                    ;restore work registers
  1089.     ENDIF
  1090.             RTS
  1091.  
  1092. ;---------------------------------------------------------------------
  1093. ;
  1094. ;    Exit from control or Status.
  1095. ;
  1096. ;---------------------------------------------------------------------
  1097.  
  1098. ExitDrvr    BTST    #NoQueueBit,ioTrap(A0)        ; no queue bit set?
  1099.             BEQ.S    GoIODone                    ; => no, not immediate
  1100.             RTS                                 ; otherwise, it was an immediate call
  1101.  
  1102. GoIODone    MOVE.L    JIODone,A0                    ; get the IODone address
  1103.             JMP     (A0)                        ; invoke it
  1104.  
  1105.  
  1106.  
  1107.  
  1108. ;=====================================================================
  1109. ;
  1110. ;    Utilities
  1111. ;
  1112. ;=====================================================================
  1113.  
  1114.  
  1115. ;---------------------------------------------------------------------
  1116. ;
  1117. ;    CvtIndex
  1118. ;
  1119. ;        Calculate the proper index for the hw dependent CLUT given a
  1120. ;        hw independent index. (for example: <0,1,2,3> => <$00,$40,$80,$C0>
  1121. ;
  1122. ;    ->    A1    : Ptr to the DCE.
  1123. ;    <-    D6    : The Index Range (1,3,15 or 255).
  1124. ;    <-    D7    : The Shift Constant (7,6,4 or 0).
  1125. ;
  1126. ;---------------------------------------------------------------------
  1127.  
  1128. ; Save registers
  1129. CvtIndex    MOVEM.L    A3/D0/D4,-(SP)                ; Save registers
  1130.  
  1131. ; Get the mode (D4). mode will be 1,2,4 or 8.
  1132.             MOVE.L    dCtlStorage(A1),A3            ; D7 <- the mode (onebitmode, twobitmode,....)
  1133.             MOVE.L    (A3),A3
  1134.             MOVE.W    saveMode(A3),D7
  1135.             SUB.W    #OneBitMode,D7                ; D7 <- (0,1,2 or 3)
  1136.             MOVEQ    #1,D4                        ; D4 <- 1 << D3  {ie. 1,2,4 or 8}
  1137.             LSL.W    D7,D4
  1138.     
  1139. ; Determine the index range (D6). Range will be in [0..n], we need to calculate n.
  1140.             MOVE.W    D4,D0                        ; D0 <- (0,1,3 or 7)
  1141.             SUBQ    #1,D0
  1142.             MOVEQ    #2,D6                        ; D6 <- (2 << D0) - 1 {ie. 1,3,15,255}
  1143.             LSL.W    D0,D6
  1144.             SUBQ    #1,D6
  1145.     
  1146. ; Determine the shift constant (D7). SC = (7,6,4 or 0).
  1147.             MOVEQ    #8,D7                        ; D7 <- (7,6,4 or 0)
  1148.             SUB.W    D4,D7
  1149.  
  1150. ; End
  1151.             MOVEM.L    (SP)+,A3/D0/D4                ; Restore registers
  1152.             RTS
  1153.  
  1154.  
  1155. ;---------------------------------------------------------------------
  1156. ;
  1157. ;    ChkMode
  1158. ;
  1159. ;    Maps the mode to a depth (1, 2, 4 or 8)
  1160. ;    Assumes DCE pointer in A1.
  1161. ;
  1162. ;    ->    D1: Mode
  1163. ;    <-    D1: Depth
  1164. ;        D0: trashed
  1165. ;
  1166. ;    Returns EQ if mode is valid.
  1167.  
  1168. ChkMode        SUB        #OneBitMode,D1        ; make it 0 based
  1169.             BMI.S    ModeBad                ; =>bad mode, return
  1170.     
  1171.             CMP        #3,D1                ; is it too big?
  1172.             BGT.S    ModeBad                ; =>yes, return
  1173.     
  1174.             MOVEQ    #1,D0                ; get a one
  1175.             LSL        D1,D0                ; convert to a depth
  1176.             MOVE    D0,D1                ; and return in D1
  1177.     
  1178.             CMP.W    #8,D1                ; requesting 8-Bit mode?
  1179.             BNE.S    @1                    ; 1,2,4 always OK
  1180.             MOVE.L    A0,-(SP)            ; save A0
  1181.             MOVE.L    dCtlStorage(A1),A0    ; get handle to private storage 
  1182.             MOVE.L    (A0),A0                ; get pointer to private storage 
  1183.             TST.B    VRAM256K(A0)        ; is there too little RAM?
  1184.             MOVE.L    (SP)+,A0            ; restore register
  1185.             BNE.S    ModeBad                ; if TRUE, then return error    
  1186. @1
  1187.     
  1188. ModeOK        CMP.W    D1,D1                ; get EQ
  1189. ModeBad        RTS                            ; EQ if valid depth
  1190.  
  1191.  
  1192. ;---------------------------------------------------------------------
  1193. ;
  1194. ;    ChkPage
  1195. ;
  1196. ;    Checks to see if the page in D0 is valid for the depth in D1.
  1197. ;   Max page numbers are 4 for 1 bit mode; 2 for 2 bit mode; 1 for 4 bit mode;
  1198. ;   and 0 for 8 bit mode.
  1199. ;    Assumes DCE pointer in A1.
  1200. ;
  1201. ;    ->    D0: Page
  1202. ;    ->  D1: Depth
  1203. ;
  1204. ;    Returns EQ if page is valid.
  1205.  
  1206. ChkPage        MOVEM.L    D2/A0,-(SP)            ; save work registers    
  1207.             MOVE.L    dCtlStorage(A1),A0    ; get private storage handle    
  1208.             MOVE.L    (A0),A0                ; get pointer to private storage 
  1209.             TST.B    VRAM256K(A0)        ; 512K or 256K?    
  1210.             BNE.S    @1                    ; if TRUE, then 256K of RAM
  1211.             MOVEQ    #4,D2                ; if FALSE, 512K vRAM (and 1 more page per mode) 
  1212.             BRA.S    @2
  1213. @1            MOVEQ    #3,D2                ; get max one bit page count    
  1214. @2            DIVU    D1,D2                ; divide by depth
  1215.             CMP        D2,D0                ; is page # too big?    
  1216.             SGT        D2                    ; set flag if too big    
  1217.             TST.B    D2                    ; and test condition    
  1218.             MOVEM.L    (SP)+,D2/A0            ; restore work registers
  1219.             RTS
  1220.     
  1221.  
  1222. ;---------------------------------------------------------------------
  1223. ; InitTFB initializes the TFB
  1224. ; All Registers preserved
  1225. ;---------------------------------------------------------------------
  1226.  
  1227. TFBInit        MOVEM.L    D0/A0/A1,-(SP)        ;save all regs
  1228.  
  1229.         ; Video card initialization
  1230.  
  1231.             MOVEM.L    (SP)+,D0/A0/A1        ;restore all regs
  1232.             RTS                            ;init done
  1233.  
  1234.  
  1235. TFBSetDepth    
  1236. ;---------------------------------------------------------------------
  1237. ; SetDepth sets the TFB depth
  1238. ; D1 contains the depth (1,2,4,8}
  1239. ; A1 = DCE pointer
  1240. ; A2 = parameter block pointer
  1241. ; A3 = dCtlStorage pointer
  1242. ; Preserves all registers
  1243. ;---------------------------------------------------------------------
  1244.  
  1245.  
  1246.             MOVEM.L    D0-D2/A0-A1,-(SP)        ;save all regs
  1247.  
  1248. ; save the new mode
  1249.  
  1250.             MOVE.W    csMode(A2),saveMode(A3)     ; save the mode    
  1251.     
  1252.         ; Set the video card depth
  1253.  
  1254.             MOVEM.L    (SP)+,D0-D2/A0-A1        ;restore all regs
  1255.             RTS                                ;return
  1256.  
  1257. TFBSetPage
  1258. ;---------------------------------------------------------------------
  1259. ; Entry:    D0 = Page # (0 based)
  1260. ;            A1 = DCE pointer
  1261. ;            A2 = parameter block pointer
  1262. ;            A3 = dCtlStorage pointer
  1263. ;
  1264. ;  The base of a page is at dCtlDevBase + 4 + (page * RowBytes * height)
  1265. ;
  1266. ;  All registers are preserved.
  1267.  
  1268.             MOVEM.L    D0-D1/A0-A1,-(SP)            ; save all registers
  1269.     
  1270.             MOVE    D0,savePage(A3)                ; save the page
  1271.             MOVE    csMode(A2),D1                ; get the mode
  1272.             SUB        #OneBitMode,D1                ; make it 0 based    
  1273.             LEA        ModeTbl,A0                    ; point to tables    
  1274.             MULU    4(A0,D1*8),D0                ; calc page * rowBytes
  1275.             MULU    6(A0,D1*8),D0                ; calc page * rowBytes * height
  1276.             MOVEQ    #defmBaseOffset,D1            ; add offset for TFB
  1277.             ADD.L    D1,D0                        ; which doesn't use first long
  1278.             MOVE.L    D0,D1                        ; save offset to page in bytes
  1279.             MOVE.L    dCtlDevBase(A1),A0            ; get base for device
  1280.             ADD.L    A0,D0                        ; add the slot's base address
  1281.             MOVE.L    D0,saveBaseAddr(A3)            ; save the base address
  1282.  
  1283. ;  Now set the hardware by writing the offset in longs to the proper registers.
  1284.  
  1285.             MOVEM.L    (SP)+,D0-D1/A0-A1            ; restore all registers
  1286.             RTS                                    ; and return
  1287.  
  1288.  
  1289. GrayScreen
  1290. ;---------------------------------------------------------------------
  1291. ;            D0 = Page
  1292. ;            A3 = dCtlStorage Ptr.
  1293. ;
  1294. ;  All registers are preserved.
  1295.  
  1296.             MOVEM.L    D0-D4/A0-A1,-(SP)            ; save all registers
  1297.             MOVE    csMode(A2),D1                ; get the mode
  1298.             SUB        #OneBitMode,D1                ; make it 0 based    
  1299.             CMP.W    #3,D1                        ; if 8-bit req, test for RAM
  1300.             BNE.S    @1                            ; 1,2,4 bit requests are always OK    
  1301.             TST.B    VRAM256K(A3)                ; is there enough RAM?
  1302.             BNE.S    GSDone                        ; if TRUE, then don't do anything    
  1303. @1            LEA        ModeTbl,A1                    ; point to tables    
  1304.             MOVE.L    0(A1,D1*8),D0                ; D0 = the proper pattern    
  1305.             MOVE    4(A1,D1*8),D4                ; D4 = rowbytes for the screen
  1306.             MOVE    6(A1,D1*8),D3                ; D3 = screen height
  1307.             SUBQ    #1,D3                        ; make it 0 based    
  1308.             MOVE.L    D0,D1                        ; get inverse of pattern    
  1309.             NOT.L    D1                            ; for alternate lines
  1310.  
  1311.             MOVE.L    saveBaseAddr(A3),A1            ; point to the current page    
  1312. NxtRow1        MOVE.L    A1,A0                        ; get next row
  1313.             MOVE.W    D4,D2                        ; get bytes per row    
  1314.             LSR        #2,D2                        ; get longs per row    
  1315.             SUBQ    #1,D2                        ; make count 0 based
  1316. NxtLong1    MOVE.L    D0,(A0)+                    ; write gray
  1317.             DBF        D2,NxtLong1                    ; for entire width of row    
  1318.             EXG        D0,D1                        ; get inverse gray for next row
  1319.             ADD.W    D4,A1                        ; bump to next row    
  1320.             DBF        D3,NxtRow1                    ; until no more rows
  1321. GSDone
  1322.             MOVEM.L    (SP)+,D0-D4/A0-A1            ; restore all registers
  1323.             RTS                                    ; and return
  1324.     
  1325.  
  1326. ; Mode info:         Pattern,RowBytes,Height
  1327.  
  1328. ModeTbl        DC.W    $AAAA,$AAAA,$0080,$01E0        ; one bit per pixel    
  1329.             DC.W    $CCCC,$CCCC,$0100,$01E0        ; two bit per pixel    
  1330.             DC.W    $F0F0,$F0F0,$0200,$01E0        ; four bit per pixel
  1331.             DC.W    $FF00,$FF00,$0400,$01E0        ; eight bit per pixel
  1332.     
  1333.  
  1334. ;-------------------------------------------------------------
  1335. ;    The Interrupt handler for TFB board
  1336. ;-------------------------------------------------------------
  1337. ; The interrupt Handler
  1338. ; On entry A1 contains the slot base address
  1339. ; D0-D3/A0-A3 have been preserved.
  1340. BeginIH        MOVE.L    A1,A0            ; get screen base
  1341.             MOVE.L    A1,D0            ; and save for later
  1342.             ADD.L    #ClrVInt,A0        ; get offset to register
  1343.             CLR.B    (A0)            ; clear interrupt from card
  1344.  
  1345.                                     ; D0 = $Fssxxxxx
  1346.             ROL.L    #8,D0            ; D0 <- $sxxxxxFs    Convert the address into 
  1347.             AND        #$0F,D0            ; D0 <- $sxxx000s    the slot number.
  1348.  
  1349.             MOVE.L    JVBLTask,A0        ; call the VBL task manager
  1350.             JSR        (A0)            ; with slot # in D0
  1351.  
  1352.             MOVEQ    #1,D0            ; signal that int was serviced
  1353.             RTS                        ; and return to caller
  1354.  
  1355.